package io.scnb.remoting.transport.netty.codec;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.scnb.serialize.Serializer;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * 自定义解码器
 */
@Slf4j
public class NettyKryoDecoder extends ByteToMessageDecoder {
    private final Serializer serializer;
    private final Class<?> genericClass;

    public NettyKryoDecoder(Serializer serializer, Class<?> genericClass) {
        this.serializer = serializer;
        this.genericClass = genericClass;
    }

    /**
     * Netty传输的消息长度，即对象序列化后对应的字节数组的大小，存储在ByteBuf头部
     */
    private static final int BODY_LENGTH = 4;

    /**
     * 解码ByteBuf对象
     * @param channelHandlerContext 解码器关联的ChannelHandlerContext对象
     * @param in    "入站“数据，也就是ByteBuf对象
     * @param out   解码之后的数据对象需要添加到out队列种
     * @throws Exception
     */
    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext,
                          ByteBuf in, List<Object> out) throws Exception {
        // 1. ByteBuf种写入的数据长度已经占了4个字节，所以bytebuf的可读字节数一定要大于4
        if (in.readableBytes() >= BODY_LENGTH) {
            //2. 标记当前readIndex的位置
            in.markReaderIndex();
            // 3. 读取消息的长度
            int dataLength = in.readInt();
            // 4. 遇到不合理的情况直接return
            if (dataLength < 0 || in.readableBytes() < 0) {
                log.error("data length of bytebuf readableBytes is not valid");
                return;
            }
            // 5. 如果可读字节数小于消息长度，说明是不完整的数据，重置readIndex
            if (in.readableBytes() < dataLength) {
                in.resetReaderIndex();
                return;
            }
            // 6. 到这一步表明没有问题，可以进行反序列化
            byte[] body = new byte[dataLength];
            in.readBytes(body);
            // 将bytes数组转换为我们需要的对象
            Object obj = serializer.deserialize(body, genericClass);
            out.add(obj);
            log.info("successful decode ByteBuf to Object");
        }
    }
}
